package com.xiaoc.bulldozer.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.google.gson.JsonObject;
import com.xc.framework.cache.manager.CacheManager;
import com.xc.framework.cache.utils.CacheUtils;
import com.xc.framework.common.exception.BusinessException;
import com.xc.framework.common.utils.HttpUtil;
import com.xiaoc.bulldozer.common.CacheKeys;
import com.xiaoc.bulldozer.common.Constant;
import com.xiaoc.bulldozer.common.WeixinConstant;
import com.xiaoc.bulldozer.common.dto.WeixinUserDto;
import com.xiaoc.bulldozer.common.dto.WxCodeConfig;
import com.xiaoc.bulldozer.service.WxService;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.spec.AlgorithmParameterSpec;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Service("wxService")
public class WxServiceImpl implements WxService {

    private static final Logger logger = LoggerFactory.getLogger(WxServiceImpl.class);

    @Value("${wechat.miniapp.appid}")
    private String appId;
    @Value("${wechat.miniapp.secret}")
    private String appSecret;

    @Resource
    private CloseableHttpClient closeableHttpClient;

    @Resource(name = "remoteCacheManager")
    private CacheManager remoteCacheManager;

    @Autowired
    private WxMaService wxService;

    @Override
    public String getAccessToken() {

        String accessToken = (String) remoteCacheManager.get(CacheUtils.generateCacheKey(CacheKeys.WX_ACCESS_TOKEN));

        logger.info("accessToken:{}", accessToken);
        if (StringUtils.isNotEmpty(accessToken)) {
            return accessToken;
        }

        Map<String, Object> params = new LinkedHashMap<String, Object>();
        params.put("grant_type", "client_credential");
        params.put("appid", appId);
        params.put("secret", appSecret);

        JsonObject json = HttpUtil.getSimpleRequestJson(closeableHttpClient, WeixinConstant.WX_ACCESS_TOKEN_URL, params);

        accessToken = json.get("access_token").getAsString();

        remoteCacheManager.put(CacheUtils.generateCacheKey(CacheKeys.WX_ACCESS_TOKEN), accessToken, Constant.ACCESS_TOKEN_SESSION_TIMEOUT);

        return accessToken;
    }



    @Override
    public File generateWxCode(String accessToken, WxCodeConfig wxCodeConfig, File wxCodeFile) {

        RestTemplate rest = new RestTemplate();
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            Map<String, Object> param = new HashMap<>();
            param.put("scene", wxCodeConfig.getScene());
            param.put("page", wxCodeConfig.getPage());
            param.put("width", wxCodeConfig.getWidth());
            param.put("auto_color", false);
            param.put("is_hyaline",wxCodeConfig.getIsHyaline());

            Map<String, Integer> lineColorMap = wxCodeConfig.getLineColor();
            if (lineColorMap == null) {
                lineColorMap = new HashMap<String, Integer>();
            }
            Integer r = lineColorMap.get("r");
            Integer g = lineColorMap.get("g");
            Integer b = lineColorMap.get("b");

            Map<String, Object> line_color = new HashMap<>();
            line_color.put("r", r == null ? 0 : r);
            line_color.put("g", g == null ? 0 : g);
            line_color.put("b", b == null ? 0 : b);
            param.put("line_color", line_color);

            String url = WeixinConstant.WX_X_CODE_URL + "?access_token=" + accessToken;

            MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
            HttpEntity requestEntity = new HttpEntity(param, headers);
            ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
            byte[] result = entity.getBody();
//            logger.info(Base64.encodeBase64String(result));
            inputStream = new ByteArrayInputStream(result);
//            if (!targetFile.exists()) {
//                targetFile.createNewFile();
//            }
            outputStream = new FileOutputStream(wxCodeFile);
            int len = 0;
            byte[] buf = new byte[1024];
            while ((len = inputStream.read(buf, 0, 1024)) != -1) {
                outputStream.write(buf, 0, len);
            }
            outputStream.flush();

        } catch (Exception e) {
            logger.error("generate wx code failed", e);
            throw new BusinessException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.error("generate wx code failed", e);
                    throw new BusinessException(e);
                }
            }
        }
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                logger.error("generate wx code failed", e);
                throw new BusinessException(e);
            }
        }

        return wxCodeFile;
    }

    @Override
    public String getPhoneNumber(WeixinUserDto user, String encryptedData, String iv) throws Exception {

//        String sessionKey = null;
//
//        if(code != null){
//            WxMaJscode2SessionResult json = wxService.getUserService().getSessionInfo(code);
//            sessionKey = json.getSessionKey();
//            user.setSessionKey(sessionKey);
//        }

        String sessionKey = user.getSessionKey();
        String jsonStr = decrypt(sessionKey,iv,encryptedData);
        JSONObject jsonObject=JSONObject.fromObject(jsonStr);
        return jsonObject.get("phoneNumber").toString();
    }

    /**
     * 微信手机号解码
     * @param sessionkey1
     * @param ivdata1
     * @param encrypdata1
     * @return
     * @throws Exception
     */
    public  String decrypt(String sessionkey1, String ivdata1, String encrypdata1) throws Exception {
            Base64 base64 = new Base64();
            byte[] encrypData = base64.decode(encrypdata1);
            byte[] ivData = base64.decode(ivdata1);
            byte[] sessionKey = base64.decode(sessionkey1);

            logger.info("sessionkey{}",sessionkey1);
            logger.info("sessionKey[]{}",sessionKey);
            AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivData);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(sessionKey, "AES");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
           return new String(cipher.doFinal(encrypData), "UTF-8");
    }

}
